/**
 * SwapMutation.java
 * Class representing a swap mutation operator
 * @author Antonio J.Nebro
 * @version 1.0
 */

package jmetal.base.operator.mutation;

import java.util.Random;

import TeamPursuit.MensTeamPursuit;
import TeamPursuit.SimulationResult;
import TeamPursuit.WomensTeamPursuit;

import P3.Strategy;
import jmetal.base.Solution;
import jmetal.util.Configuration;
import jmetal.util.JMException;
import jmetal.base.operator.mutation.Mutation;

/**
 * This class implements a swap mutation. NOTE: the operator is applied to the
 * first variable of the solutions, and the type of those variables must be
 * <code>VariableType_.Permutation</code>.
 */
public class MyMutation extends Mutation {
	private static final double pOnPacing=0.1; 
	private static final double pOnBigPacing=0.1;
	private static final double pOnBigPower=0.6;
	/**
	 * Performs the operation
	 * 
	 * @param probability
	 *            Mutation probability
	 * @param solution
	 *            The solution to mutate
	 * @throws JMException
	 */
	public void doMutation(double probability, Solution solution)
			throws JMException {
		SimulationResult result = null;
		Random r = new Random();
		Strategy str1 = (Strategy) solution.getDecisionVariables()[0];

		int[] power = str1.getPower();
		boolean[] pacing = str1.getPacing();
		
		double p=r.nextDouble();
		if(p>probability)
			return;
		
		do{
			p=r.nextDouble();
			if (p < probability) {
				smallMutate(power);
			} // if
			if (p < pOnBigPower) {
				bigMutate(power);
			} // if
			if(p < pOnPacing){
				smallMutate(pacing);
			}
			if(p < pOnBigPacing){
				bigMutate(pacing);
			}
			try {
				if(solution.getType().typename.equalsIgnoreCase("men")){
					MensTeamPursuit teamPursuit = new MensTeamPursuit();
					result = teamPursuit.simulate(pacing, power);
				}
				else if(solution.getType().typename.equalsIgnoreCase("women")){
					WomensTeamPursuit teamPursuit = new WomensTeamPursuit();
					result = teamPursuit.simulate(pacing, power);
				}
				else{
					System.out.println("Error") ;
					System.exit(-1) ;
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}while(!isValid(result));
		
	} // doMutation

	private boolean[] smallMutate(boolean[] a) {
		int len = a.length;

		// generate position randomly
		Random r = new Random();
		int position = r.nextInt(len);
		a[position] = r.nextBoolean();
		return a;
	}

	private int[] smallMutate(int[] a) {

		int len = a.length;
		Random r = new Random();
		int start = r.nextInt(len);
		a[start] = r.nextInt(1001) + 200;
		return a;
	}
	private boolean[] bigMutate(boolean[] a) {
		int len=a.length;
		int temp;
		//generate position randomly
		Random r=new Random();
		int position1=r.nextInt(len);
		int position2=r.nextInt(len);
		if(position1>position2){
			temp=position1;
			position1=position2;
			position2=temp;
		}
		//randomly generate it
		for(int i=position1;i<=position2;i++){
			a[i]=r.nextBoolean();	
		}
		return a;
	}

	private int[] bigMutate(int[] a) {

		int len=a.length;
		int temp;
		//generate two distinct positions randomly
		Random r=new Random();

		int position1=r.nextInt(len);
		int position2=r.nextInt(len);
		if(position1>position2){
			temp=position1;
			position1=position2;
			position2=temp;
		}
		//randomly generate them
		for(int i=position1;i<position2;i++){
			a[i]=r.nextInt(801)+200;	
		}
		return a;
	}
	private boolean isValid(SimulationResult result){
		if(result.getProportionCompleted() < 0.9999998){
			return false;
		}else{
			return true;
		}
	}
	/**
	 * Executes the operation
	 * 
	 * @param object
	 *            An object containing the solution to mutate
	 * @return an object containing the mutated solution
	 * @throws JMException
	 */
	public Object execute(Object object) throws JMException {
		Solution solution = (Solution) object;

		Double probability = (Double) getParameter("probability");
		if (probability == null) {
			Configuration.logger_.severe("SwapMutation.execute: probability "
					+ "not specified");
			Class cls = java.lang.String.class;
			String name = cls.getName();
			throw new JMException("Exception in " + name + ".execute()");
		}

		this.doMutation(probability.doubleValue(), solution);
		return solution;
	} // execute
} // SwapMutation
